#![no_std]
#![no_main]
#![feature(naked_functions)]

extern crate alloc;

use alloc::{
    collections::btree_map::BTreeMap,
    format,
    string::{String, ToString},
    vec::Vec,
};
use syscall::{op::get_cwd, op_ext::read_line};

#[macro_use]
extern crate syscall;

mod commands;
mod run;
use commands::*;

mod malloc;

fn get_prompt() -> String {
    format!(
        "\x1b[36m[\x1b[34mroot@vmx \x1b[33m{}\x1b[36m]\x1b[34m:) \x1b[0m",
        get_cwd()
    )
}

type CommandFunction = fn(args: Vec<String>);

fn exit(_args: Vec<String>) {
    syscall::op::exit(0);
}

#[unsafe(no_mangle)]
pub fn _start(_argc: usize, _argv: usize) -> usize {
    let mut command_function_list = BTreeMap::<&str, CommandFunction>::new();

    {
        command_function_list.insert("cd", cd);
        command_function_list.insert("ls", ls);
        command_function_list.insert("cat", cat);
        command_function_list.insert("exit", exit);
        command_function_list.insert("write", write);
    }

    let mut input_buf = String::new();

    loop {
        print!("{}", get_prompt());

        read_line(&mut input_buf);

        println!();

        let input =
            String::from_utf8(escape_bytes::unescape(input_buf.as_bytes()).unwrap()).unwrap();

        let args = input.split(" ").map(|x| x.to_string()).collect::<Vec<_>>();

        let function = command_function_list.get(&args[0].as_str());

        if let Some(function) = function {
            function(args);
        } else if let None = run::try_run(args[0].clone(), input.as_str()) {
            println!("Command not found: {}", args[0]);
        }
    }
}

#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
    println!("{}", info);
    syscall::op::exit(1)
}
